﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TVGuide.DataAccess.Common;
using TVGuide.DataAccess.Exceptions;

namespace TVGuide.DataAccess.Repository
{
    public class ChannelRepository : IChannelRepository
    {
        #region Singleton pattern

        private static tvchanneldbEntities model;
        private static ChannelRepository instance;

        private ChannelRepository() 
        {
            model = new tvchanneldbEntities();
            maxId = model.channels.Max(o => o.channelID);
        }

        public static ChannelRepository Instance()
        {
            if (instance == null)
                instance = new ChannelRepository();
            return instance;
        }

        #endregion

        #region IRepository<Channel> Members

        public void Add(Channel item)
        {
            Add(item, true);
        }
        
        public void Add(Channel item, bool commitChange)
        {
            if (item == null)
                throw new InvalidArgsException("The parameter is null");

            if (String.IsNullOrEmpty(item.Name))
                throw new InvalidArgsException("The 'channelName'property is null");

            if (item.Date == null)
                throw new InvalidArgsException("The 'date'property is null");

            if (item.Date < new DateTime(2000, 01, 01))
                throw new InvalidArgsException("Invalid 'Date': The date should be not older 01.01.2010.");

            try
            {
                if (item.LanguageId > 0 && model.languages.FirstOrDefault(o => o.languageID == item.LanguageId) == null)
                    throw new InvalidArgsException("Invalid 'languageId'");
            }
            catch (InvalidOperationException)
            {
                throw new InvalidArgsException("Invalid 'languageId'");
            }

            if (maxId > 0 && model.channels.FirstOrDefault(o => o.channelName.Equals(item.Name)) != null)
                throw new InvalidArgsException("This channel already exsists");

            // No channel Id provided, we must provide
            if (item.Id == 0)
            {
                if (maxId == 0)
                    item.Id = 1;
                else
                    item.Id = (short)++maxId;
            }
            // Channel Id provided
            else
            {
                if (model.channels.FirstOrDefault(o => o.channelID == item.Id) != null)
                    throw new InvalidArgsException("Invalid id, this id already exsists");
            }

            model.channels.AddObject((channel)item);
            if(commitChange)
                model.SaveChanges();
            //return item.Id;
        }

        public void AddRange(IEnumerable<Channel> items)
        {
            try
            {
                foreach (var item in items)
                {
                    Add(item, false);
                }
            }
            catch (InvalidArgsException e)
            {
                // TODO rollback changes.
                InvalidArgsException ex = new InvalidArgsException(e.Message + "\nNo items were committed.");
                throw ex;
            }
            model.SaveChanges();
        }

        public Channel Get(int id)
        {
            return (Channel)model.channels.FirstOrDefault(o => o.channelID == id);
        }

        public IEnumerable<Channel> Get(Predicate<Channel> func)
        {
            List<Channel> list = new List<Channel>();            
            foreach (var item in model.channels)
            {
                Channel cloneObj = (Channel)item;
                if (func((Channel)item))
                    list.Add(cloneObj);
            }
            return list;
        }

        public IEnumerable<Channel> GetAllItems()
        {
            return Get(o => true).OrderBy(o=>o.Enabled);
        }

        public void Remove(int id)
        {
            channel ch = model.channels.FirstOrDefault(o => o.channelID == id);
            if(ch != null)
                model.channels.DeleteObject(ch);
            model.SaveChanges();
        }

        public void Remove(Predicate<Channel> func)
        {
            List<channel> removeList = new List<channel>();
            foreach (var item in model.channels)
            {
                if (func((Channel)item))
                    removeList.Add(item);
            }
            foreach (var item in removeList)
            {
                model.channels.DeleteObject(item);
            }
            model.SaveChanges();
        }

        public void RemoveAll()
        {
            Remove(o => true);
        }

        #endregion

        private int maxId;
    }
}
